// 手写 Promise
// const p1 = new Promise((resolve, reject) => {
//     resolve('成功')
//     console.log('后续会发生什么呢？')
//     reject('失败')
//     console.log('后续会发生什么呢？')
// })

// console.log('p1', p1)

// const p2 = new Promise((resolve, reject) => {
//     reject('失败')
//     console.log('后续会发生什么呢？')
//     resolve('成功')
//     console.log('后续会发生什么呢？')
// })

// console.log('p2', p2)

// const p3 = new Promise((resolve, reject) => {
//     console.log('后续会发生什么呢？')
//     throw new Error('报错')
//     console.log('后续会发生什么呢？')
// })

// console.log(p3)

/**
 * 以上代码：
 * 1.执行了 resolve 方法，Promise 状态会变成 fulfilled，即成功
 * 2.执行了 reject 方法，Promise 状态会变成 rejected，即失败
 * 3.Promise 只以第一次状态变更为准，也只会有一次状态变更
 * 4.Promise 中有 throw 的话，相当于执行了 reject，但是与 reject 有一定区别，reject 后的代码依旧会执行，但是 throw 后的代码并不会执行
 */

class PromiseByCy {
    constructor(executor) {
        // 初始化值
        this.initValue()
        // 初始化 this 指向，保证 resolve 和 reject 方法中的 this 永远指向当前 Promise 实例，而不会随着执行环境中的 this 而变更
        this.initBind()
        try {
            // 执行 executor
            executor(this.resolve, this.reject)
        } catch (error) {
            // 在 executor 中 throw 错误的话会在这里处理，同时满足 throw --> reject 的操作和 throw 后的代码不会执行的要求
            this.reject(error)
        }
    }
    initValue() {
        // 初始化值与状态
        this.PromiseResult = null
        this.PromiseState = 'pending'

        // 回调数组初始化
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
    }
    initBind() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }
    resolve(value) {
        if (this.PromiseState !== 'pending') {
            return
        }
        this.PromiseResult = value
        this.PromiseState = 'fulfilled'
        while (this.onFulfilledCallbacks.length) {
            this.onFulfilledCallbacks.shift()(this.PromiseResult)
        }
    }
    reject(reason) {
        if (this.PromiseState !== 'pending') {
            return
        }
        this.PromiseResult = reason
        this.PromiseState = 'rejected'
        while (this.onRejectedCallbacks.length) {
            this.onRejectedCallbacks.shift()(this.PromiseResult)
        }
    }
    then(onFulfilled, onRejected) {
        // 接收两个回调函数
        // 参数校验，保证回调必定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : res => res
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }

        if (this.PromiseState === 'fulfilled') {
            onFulfilled(this.PromiseResult)
        } else if (this.PromiseState === 'rejected') {
            onRejected(this.PromiseResult)
        } else if (this.PromiseState === 'pending') {
            this.onFulfilledCallbacks.push(onFulfilled.bind(this))
            this.onRejectedCallbacks.push(onRejected.bind(this))
        }
    }
}

/**
 * 测试代码暴露出一个问题，自定义的 Promise 状态是可变的，并没有实现一变即冻的效果
 * 因此在 resolve 和 reject 方法中再加一层判断，如果状态不是 pending 就退出
 */

// const p1 = new PromiseByCy((resolve, reject) => {
//     resolve('成功')
//     reject('失败')
// })

// console.log(p1)

/**
 * then 方法几个特点
 * 1.接收两个回调，一个成功回调，一个失败回调
 * 2.fulfilled 调用成功回调，rejected 调用失败回调
 * 3.如果 resolve 和 reject 在异步操作中，等异步操作结束后才会执行 then
 * 4.then 方法支持链式调用，下一次 then 执行受上一次 then 返回值的影响
 */
// const p1 = new Promise((resolve, reject) => {
//     resolve('成功')
// }).then(res => {
//     console.log(res)
// }, err => {
//     console.log(err)
// })

// const p2 = new Promise((resolve, reject) => {
//     setTimeout(() => {
//         reject('失败')
//     }, 1000)
// }).then(res => {
//     console.log(res)
// }, err => {
//     console.log(err)
// })

// // then 的链式调用
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(100)
    }, 1000)
}).then(res => {
    console.log('then1')
    return res * 2
}, err => {
    console.log('err1')
    console.log(err)
}).then(res => {
    console.log('then2')
    console.log(res)
}, err => {
    console.log('err2')
    console.log(err)
})
